----CEC 251 VHDL code  Spring/2009
----Fabric group----
----Fabiric-Table SM -- Communication procedure between Fabric and Table 
----code by Wenzhong Wu  Data  2/19/2009
----Version 1.02     
----Last Modifyed by Wenzhong Wu Data 3/19/2009
library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
use IEEE.STD_LOGIC_ARITH.ALL; 
use IEEE.STD_LOGIC_UNSIGNED.ALL;
USE ieee.numeric_std.all;
LIBRARY lpm;
USE lpm.lpm_components.ALL;

ENTITY Mac_Table IS
	GENERIC ( MAC_len: INTEGER:= 6; -- source and destination mac address 6 bytes
			  Input_port_num_bit: INTEGER:= 2;  --2 bits for input port number
			  output_port_num_bit: INTEGER:= 3;	--3 bits for output port number
			  Mac_num_bit: INTEGER:= 8;
			  Counter_num_bit:INTEGER:=4
			  
    );
    Port ( 
		reset:In STD_LOGIC;
		clk : In STD_LOGIC; 
        Mac_ready : In STD_LOGIC;
        Input_data: In STD_LOGIC_VECTOR(7 downto 0);
        Input_port_num: In STD_LOGIC_VECTOR(Input_port_num_bit-1 downto 0);
		Destination_output_portNum_table : In STD_LOGIC_VECTOR (Input_port_num_bit-1 downto 0);
		Destination_output_portNum : Out STD_LOGIC_VECTOR (output_port_num_bit-1 downto 0);
		Table_OutputP_ready: In STD_LOGIC; 
		Bload_cast: in STD_LOGIC;
		
		Source_portN: Out STD_LOGIC_VECTOR(Input_port_num_bit-1 downto 0);
		Table_request: Out STD_LOGIC;
		OutPort_read_Done: Out STD_LOGIC;
		
		Sr_Mac_add : Out STD_LOGIC_VECTOR(7 downto 0);
		Dn_Mac_add : Out STD_LOGIC_VECTOR(7 downto 0)
 
    );           
end Mac_Table;


ARCHITECTURE Behav OF Mac_Table IS

        TYPE MAC_VECTOR_ARRAY IS ARRAY (MAC_len-1 DOWNTO 0) of STD_LOGIC_VECTOR(7 downto 0);
        Type Mac_table_state is (s0,s1,s3,s4,s5);
        Signal  Table_OutP_ready :STD_LOGIC;
        Signal  Mac_current_state: Mac_table_state;
        Signal  Mac_next_state: Mac_table_state;
        Signal  Mac_address :  STD_LOGIC_VECTOR(7 downto 0) ;
        Signal  Dn_Mac :  MAC_VECTOR_ARRAY ;
        SIGNAL  Dn_Mac_reg_en : STD_LOGIC;
        SIGNAL  Outport_reg_en : STD_LOGIC;
        SIGNAL  Counter_sset : STD_LOGIC;
        Signal  Inport_reg_en : STD_LOGIC;
        Signal  Mac_cnter: STD_LOGIC_VECTOR(3 downto 0);
        Signal  Des_O_portNum1 :  STD_LOGIC_VECTOR (output_port_num_bit-2 downto 0);
        Signal  Des_O_portNum2 :  STD_LOGIC_VECTOR (output_port_num_bit-1 downto 0);
        Signal  Sour_P: STD_LOGIC_VECTOR(Input_port_num_bit-1 downto 0) ;
Begin
     
      Mac_counter0 : lpm_counter
			GENERIC MAP (LPM_WIDTH => Counter_num_bit,LPM_SVALUE=>"0000")
			PORT MAP (clock => clk,
						sclr => Counter_sset,
						q => Mac_cnter
						);

------- Register for source port number    
    Input_portnum: lpm_ff GENERIC MAP ( LPM_WIDTH => Input_port_num_bit )
                          port map (data=>Input_port_num,clock=>clk,enable=>Inport_reg_en,q=>Sour_P);
------- Register for output port number	
    Output_portnum: lpm_ff GENERIC MAP ( LPM_WIDTH => output_port_num_bit )
                          port map (data=>Des_O_portNum2,clock=>clk,enable=>Outport_reg_en,q=>Destination_output_portNum);
		
	


--------Registers for Desination MAC Address
	Dn_Mac_Reg5 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Mac_address,enable=>Dn_Mac_reg_en,q=>Dn_Mac(5));
	Dn_Mac_Reg4 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(5),enable=>Dn_Mac_reg_en,q=>Dn_Mac(4));
	Dn_Mac_Reg3 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(4),enable=>Dn_Mac_reg_en,q=>Dn_Mac(3));
	Dn_Mac_Reg2 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(3),enable=>Dn_Mac_reg_en,q=>Dn_Mac(2));
	Dn_Mac_Reg1 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(2),enable=>Dn_Mac_reg_en,q=>Dn_Mac(1));
	Dn_Mac_Reg0 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(1),enable=>Dn_Mac_reg_en,q=>Dn_Mac(0));

	
	Source_portN <=Sour_P;
	Mac_address<=Input_data;
	
	Process (clk,reset)
    begin
						if (Bload_cast='1') then
	                           case Sour_P Is
	                                When "00" =>
										Des_O_portNum2<="101";
									When "01" =>
										Des_O_portNum2<="110";
									When "10" =>
										Des_O_portNum2<="111";
									When "11" =>	
										Des_O_portNum2<="100";
								end case;
							else
								Des_O_portNum2<='0'&Destination_output_portNum_table(1 downto 0);
							end if;
	  end process;
		
		PROCESS (clk,reset) --State update process
		BEGIN
		IF ((reset = '1')) THEN --check for reset
			Mac_current_state <= s0;

		ELSIF (clk = '1' AND clk'event) THEN --At the rising edge of clock, update states
			Mac_current_state<= Mac_next_state;
		END IF;
		END PROCESS;
		


--- Mac_Table SM		
	Mac_Table :Process (clk,Mac_current_state,Mac_ready,Mac_cnter,Table_OutputP_ready,Sour_P,Bload_cast,Des_O_portNum1)
		Begin
                
                Inport_reg_en <='0';
				Dn_Mac_reg_en <='0';
--				Sr_Mac_reg_en <='0';	
				Table_request <='0';
				Outport_reg_en<='0';
				OutPort_read_Done<='0';
--				Des_O_portNum2 <= (others =>'0');
				Counter_sset <= '1';	  
				Case Mac_current_state Is
					When s0 =>
					   if (Mac_ready ='1')then
							Mac_next_state <= s1;
							Counter_sset <= '0';
					   else 
							Counter_sset <= '1';
							Mac_next_state <= s0;
					   end if;	
				    When s1 =>
				       if (Mac_cnter <"0111")then
                           if (Mac_cnter ="0001")then
						      Inport_reg_en <='1';
						   else
                              Inport_reg_en <='0';
                           end if;		
                           Dn_Mac_reg_en <='1';
                           Counter_sset <= '0';
                           Mac_next_state <= s1; 
 					   else 
						   Mac_next_state <= s3;  ----
                       end if;		
					When s3 =>          ---   send MAC address to the table;
                        Table_request <='1';
						if (Mac_cnter <"0101")then
							Counter_sset <= '0';
							Mac_next_state <= s3;
						else 
							Mac_next_state <= s4;
							Counter_sset <= '1';
						end if;
					When s4 =>
						 if (Table_OutputP_ready ='1') then

	                        Outport_reg_en<='1';	
	                        Mac_next_state<=s5;
	                     else
							Mac_next_state<=s4;
						 end if;
					When s5 =>
						 	
						 OutPort_read_Done <='1';
						 Mac_next_state<=s0;
					end case;	 
	End Process Mac_Table;
	

	
----Sending Mac addresses to Table-Management system 	
	Output_logic: process (Mac_current_state,Dn_Mac,Mac_cnter)
    Begin

		 case Mac_current_state is

         When s3 =>
         Sr_Mac_add <= Mac_address;
		 Dn_Mac_add <= Dn_Mac(conv_integer(Mac_cnter));
		 
		 
		 when others =>
		 Sr_Mac_add <= (others =>'0');
		 Dn_Mac_add <= (others =>'0');	
		 end case;			
    End Process Output_logic;
end Behav;        